package com.zhengxing.jienci.redis.aspectj;

import com.zhengxing.jienci.redis.annotation.SaveCache;
import com.zhengxing.jienci.redis.enums.CacheType;
import com.zhengxing.jienci.redis.util.BeanUtils;
import com.zhengxing.jienci.redis.util.KeyUtils;
import com.zhengxing.jienci.redis.util.RedisUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;

/**
 * @author 浪遏飞舟
 * @create 2020-06-18 15:02
 * 保存缓存切面
 */
@Configuration
@Aspect
@Order(2)
public class SaveCacheAspect {

    @Autowired
    private RedisUtils redisUtils;

    @Pointcut("@annotation(com.zhengxing.jienci.redis.annotation.SaveCache)")
    public void pointcut(){}

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        //获得SaveCache注解的属性值
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        SaveCache annotation = method.getAnnotation(SaveCache.class);
        //获得key
        String key = KeyUtils.getCacheKey(annotation, point);
        Object data = null;
        CacheType cacheType = annotation.type();
        String type = "";
        try {
            switch (cacheType) {
                case KV:
                    data = redisUtils.getMap(key);
                    type = "KV";
                    break;
                case LIST:
                    data = redisUtils.getListAll(key);
                    type = "LIST";
                    break;
                case STR:
                    type = "STR";
                    data = redisUtils.getStr(key);
                    break;
            }
            if (!isNull(data)) {
                //根据返回值判断能不能直接返回
                Object instance = method.getReturnType().newInstance();
                if (instance instanceof Map || instance instanceof Collection || instance instanceof String || instance instanceof Number){
                    return data;
                }else{
                    //实体类对象需要将map转为实体类
                    if (type.equals("KV")){
                        return BeanUtils.mapToBean((Map)data,method.getReturnType());
                    }
                    return data;
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        Object result = point.proceed();
        //过期时间
        long expire = annotation.expire();
        around(key,cacheType,expire,result);
        return  result;
    }


    /**
     * 判断是否为空
     * @param data
     * @return
     */
    public boolean isNull(Object data){
        if (data instanceof Map){
            if (data != null && ((Map)data).size() > 0){
                return false;
            }
        }
        if (data instanceof Collection){
            if (data != null && ((Collection)data).size() > 0){
                return false;
            }
        }
        if (data instanceof String){
            if (data != null && ((String)data).length() > 0){
                return false;
            }
        }
        return true;
    }

    /*public Map getYesResult(Object data){
        HashMap<Object, Object> result = new HashMap<>();
        result.put("result","0000");
        result.put("data",data);
        result.put("msg","");
        return result;
    }*/




    /**
     * 方法后置增强
     * @param key 键
     * @param cacheType 数据类型
     * @param result 需要缓存的数据
     * @return
     */
    public void around(String key,CacheType cacheType,long time,Object result){
        if(isNull(result) && result == null){
            return;
        }
        try {
            //根据类型区分
            switch (cacheType){
                case KV:
                    if (result instanceof Map) {
                        redisUtils.setMap(key,(Map)result);
                    }else{
                        redisUtils.setBean(key,result);
                    }
                    break;
                case LIST:
                    redisUtils.setListByTail(key,(Collection) result);
                    break;
                case STR:
                    redisUtils.setStr(key,result);
                    break;
            }
            if (time != -1 && time > 0){
                redisUtils.expireBySeconds(key,time);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }






}
